import { getBestCombResult } from './worker-mixin'

import type {
  IChefCookableRecipes,
  IBestCombResult,
  IWorkerInputMessage,
  IWorkerOutputMessage,
  ISettings,
} from './types'

self.onmessage = (event: MessageEvent<IWorkerInputMessage>) => {
  const data = event.data
  if (data.type === 'start') {
    const bestCombResult = getCombination(data.chefCombinations, data.settings)
    const messageData: IWorkerOutputMessage = {
      type: 'end',
      bestCombResult,
    }
    self.postMessage(messageData)
    self.close()
  }
}

self.onerror = () => {
  self.close()
}

function getCombination(chefCombinations: IChefCookableRecipes[][], settings: ISettings) {
  const { maxRecipeCount } = settings

  let bestCombResult: IBestCombResult = {
    totalRevenue: 0,
    workingTime: 0,
    combination: [],
  }

  for (const chefCombo of chefCombinations) {
    // 对于每组厨师，尝试为他们分配菜谱
    const currentChefsRecipes: IChefCookableRecipes[] = []
    const chosenRecipesPool = new Set<number>() // 记录当前组合中已经选择的菜谱ID，确保全局不重复

    const messageData: IWorkerOutputMessage = {
      type: 'progress',
      progressStep: 1,
    }
    self.postMessage(messageData)

    // 开始递归分配菜谱
    findRecipeAssignments(currentChefsRecipes, 0)
    function findRecipeAssignments(currentAssignment: IChefCookableRecipes[], chefIndex: number) {
      // 终止条件：所有厨师都已分配菜谱
      if (chefIndex === chefCombo.length) {
        let comboWorkingTime = 0
        let comboRevenue = 0
        const combination: IChefCookableRecipes[] = []

        currentAssignment.forEach((assignment) => {
          const { cookable } = assignment
          const recipesCookedByChef: number[] = []
          for (const { recipeId, batchRevenue, batchTime } of cookable) {
            comboWorkingTime += batchTime
            comboRevenue += batchRevenue
            recipesCookedByChef.push(recipeId)
          }
          combination.push(assignment)
        })

        bestCombResult = getBestCombResult(
          {
            totalRevenue: comboRevenue,
            workingTime: comboWorkingTime,
            combination: combination,
          },
          bestCombResult,
          settings,
        )

        return
      }

      const currentChef = chefCombo[chefIndex]
      const cookableRecipes = currentChef.cookable

      // 递归选择当前厨师的菜谱
      selectRecipesForChef([], 0)
      function selectRecipesForChef(
        chefRecipes: IChefCookableRecipes['cookable'],
        recipeIndex: number,
      ) {
        // 终止条件：当前厨师已选择3份菜谱
        if (chefRecipes.length === maxRecipeCount) {
          // 将当前厨师及其菜谱加入到总分配中
          currentAssignment.push({
            chefId: currentChef.chefId,
            cookable: [...chefRecipes],
          })
          // 递归进入下一位厨师的菜谱分配
          findRecipeAssignments(currentAssignment, chefIndex + 1)
          // 回溯：移除当前厨师的分配，尝试其他组合
          currentAssignment.pop()
          return
        }

        // 终止条件：没有更多菜谱可以选择了
        if (recipeIndex >= cookableRecipes.length) {
          return
        }

        // 尝试选择当前菜谱
        const currentRecipe = cookableRecipes[recipeIndex]
        const recipeId = currentRecipe.recipeId

        // 如果该菜谱未被全局使用过
        if (!chosenRecipesPool.has(recipeId)) {
          chosenRecipesPool.add(recipeId) // 标记为已选择
          chefRecipes.push(currentRecipe) // 加入当前厨师的菜谱列表

          // 跳过当前菜谱，尝试选择下一个菜谱
          selectRecipesForChef(chefRecipes, recipeIndex + 1)
          // 回溯：移除当前菜谱，尝试下一个菜谱的组合
          chefRecipes.pop()

          chosenRecipesPool.delete(recipeId) // 解除标记
        }

        // 跳过当前菜谱，尝试选择下一个菜谱
        selectRecipesForChef(chefRecipes, recipeIndex + 1)
      }
    }
  }

  return bestCombResult
}
